package main;

import java.awt.BasicStroke;
import java.awt.Button;
import java.awt.Choice;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;

public class HeroicFightUI extends FightUI {
	public HeroicFightMouse myMouse;
	public Panel targetStats;
	
	public static enum choosingHeroes {FIRST, COUNTER, MULTIPLE, FIGHTING, MOVING, NONE};
	public choosingHeroes choosingHero;
	public int selectingArmy = 0;
	
	public Button goodHeroicFight;
	public Button badHeroicFight;
	public Button skipHeroicFight;
	
	public Button counterCall;
	public Button skipCounter;
	
	public boolean bothChoosing;
	public Button doneChoosing;
	
	public Button doneMoving;
	
	public Hero currentHero;
	public ArrayList<Hero> callingHeroes;
	public ArrayList<Unit> movingUnits;
	
	public ArrayList<Button> moveOptions = new ArrayList<Button>();
	
	public void beginPhase() {
		myUI.selectedUnit = null;
		myUI.targetedUnit = null;
		myUI.endPhase.setEnabled(false);
		
		currentHero = null;
		callingHeroes = new ArrayList<Hero>();
		movingUnits = new ArrayList<Unit>();
		
		choosingHero = HeroicFightUI.choosingHeroes.NONE;
		
		if (!this.heroicFightPossible(Game.GOODINDEX) &&
				!this.heroicFightPossible(Game.BADINDEX)) {
			this.endPhase();
			return;
		}
		
		
		bothChoosing = true;
		selectingArmy = (myUI.game.priority+1)%2;
		
		// Need to change any button that can end a fight to set choosingHero to MOVING
		
		myMouse = new HeroicFightMouse();
		myMouse.myUI = myUI;
		myMouse.myFightUI = this;
		myUI.addMouseListener(myMouse);
		myUI.addMouseMotionListener(myMouse);
		
		targetStats = myUI.buildStatsPanel("Target", myUI.dim.width-200, myUI.dim.height-250);
		myUI.add(targetStats);
		
		// Set up fight buttons, but make all invisible
		setupButtons();
		fightBattle.setVisible(false);
		
		
		goodHeroicFight = new Button("Good Heroic Fight");
		goodHeroicFight.setBounds(myUI.dim.width-100,50,100,50);
		goodHeroicFight.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				goodHeroicFight.setVisible(false);
				badHeroicFight.setVisible(false);
				skipHeroicFight.setVisible(false);
				selectingArmy = Game.GOODINDEX;
				UI.messageLog.add("Good, select a hero to call the fight");
				choosingHero = HeroicFightUI.choosingHeroes.FIRST;
				myUI.repaint();
			}
		});
		myUI.add(goodHeroicFight);
		if (!this.heroicFightPossible(Game.GOODINDEX))
			goodHeroicFight.setEnabled(false);
		
		badHeroicFight = new Button("Bad Heroic Fight");
		badHeroicFight.setBounds(myUI.dim.width-100,100,100,50);
		badHeroicFight.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				goodHeroicFight.setVisible(false);
				badHeroicFight.setVisible(false);
				skipHeroicFight.setVisible(false);
				selectingArmy = Game.BADINDEX;
				UI.messageLog.add("Bad, select a hero to call the fight");
				choosingHero = HeroicFightUI.choosingHeroes.FIRST;
				myUI.repaint();
			}
		});
		myUI.add(badHeroicFight);
		if (!this.heroicFightPossible(Game.BADINDEX))
			badHeroicFight.setEnabled(false);
		
		
		skipHeroicFight = new Button("Skip Heroic Fight");
		skipHeroicFight.setBounds(myUI.dim.width-100,150,100,50);
		skipHeroicFight.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				endPhase();
			}
		});
		myUI.add(skipHeroicFight);
		
		
		counterCall = new Button("Counter call?");
		counterCall.setBounds(myUI.dim.width-100,50,100,50);
		counterCall.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				UI.messageLog.add(Game.armyTitles[selectingArmy] + ", select a hero to counter the call");
				choosingHero = HeroicFightUI.choosingHeroes.COUNTER;
				myUI.repaint();
			}
		});
		myUI.add(counterCall);
		counterCall.setVisible(false);
		
		skipCounter = new Button("Skip counter");
		skipCounter.setBounds(myUI.dim.width-100, 100, 100, 50);
		skipCounter.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				counterCall.setVisible(false);
				skipCounter.setVisible(false);
				
				int newSelectingArmy = (selectingArmy+1)%2;
				
				// If the other guys can add more callers, let them
				if (heroicFightPossible(newSelectingArmy)) {
					selectingArmy = newSelectingArmy;
					UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call or select done");
					choosingHero = HeroicFightUI.choosingHeroes.MULTIPLE;
					bothChoosing = false;
					doneChoosing.setVisible(true);
				}
				
				// Otherwise, just be done
				else {
					UI.messageLog.add(Game.armyTitles[newSelectingArmy] + " is out of heroes that can call a fight");
					choosingHero = HeroicFightUI.choosingHeroes.FIGHTING;
					doneMoving.setVisible(true);
					advanceFighters();
				}
				myUI.repaint();
			}
		});
		myUI.add(skipCounter);
		skipCounter.setVisible(false);
		
		
		doneChoosing = new Button("Done choosing");
		doneChoosing.setBounds(myUI.dim.width-100, 50, 100, 50);
		doneChoosing.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				int newSelectingArmy = (selectingArmy+1)%2;
				// If both were choosing, advance to other army and notify that both aren't anymore
				if (bothChoosing) {
					bothChoosing = false;
					selectingArmy = newSelectingArmy;
					// If we also don't have any more heroes to call, end it
					if (!heroicFightPossible(selectingArmy)){
						UI.messageLog.add(Game.armyTitles[selectingArmy] + " is out of heroes that can call a fight");
						choosingHero = HeroicFightUI.choosingHeroes.FIGHTING;
						doneMoving.setVisible(true);
						advanceFighters();
					}
				}
				// Otherwise, we're done choosing for good and we can start moving
				else {
					choosingHero = HeroicFightUI.choosingHeroes.FIGHTING;
					advanceFighters();
				}
				myUI.repaint();
			}
		});
		myUI.add(doneChoosing);
		doneChoosing.setVisible(false);
		
		doneMoving = new Button("Done Moving");
		doneMoving.setBounds(myUI.dim.width-100,50,100,50);
		doneMoving.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				advanceFighters();
				myUI.repaint();
			}
		});
		myUI.add(doneMoving);
		doneMoving.setVisible(false);
		
		
		
		myUI.revalidate();
		myUI.repaint();
	}
	
	private boolean heroicFightPossible(int armyIndex) {
		for (Unit u : myUI.game.armies[armyIndex].units){
			if (u instanceof Hero && u.mightLeft > 0 && 
					u.battle != null && !callingHeroes.contains((Hero)u)
					&& !u.isTransfixed)
				return true;
		}
		return false;
	}
	
	
	public void addFirstCaller(Hero hero) {
		// Assumption is that the Heroic fight buttons are already hidden

		UI.messageLog.add(hero.toChoiceString() + " is calling a heroic fight!");
		// Add him to the calling heroes list
		callingHeroes.add(hero);
		
		// If we can counter call, enable the buttons and set choosingHero to none
		int newSelectingArmy = (this.selectingArmy+1)%2;
		if (this.heroicFightPossible(newSelectingArmy)) {
			this.selectingArmy = newSelectingArmy;
			UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose whether or not to counter the call");
			this.choosingHero = HeroicFightUI.choosingHeroes.NONE;
			this.counterCall.setVisible(true);
			this.skipCounter.setVisible(true);
		}
		// Otherwise, set to multiple if we have more options
		else if (this.heroicFightPossible(this.selectingArmy)) {
			UI.messageLog.add(Game.armyTitles[newSelectingArmy] + " has no heroes that can counter call");
			UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call or select done");
			this.choosingHero = HeroicFightUI.choosingHeroes.MULTIPLE;
			this.bothChoosing = false;
			this.doneChoosing.setVisible(true);
		}
		
		// Otherwise, just be done
		else {
			UI.messageLog.add(Game.armyTitles[newSelectingArmy] + " has no heroes that can counter call");
			UI.messageLog.add(Game.armyTitles[selectingArmy] + " is out of heroes that can call a fight");
			this.choosingHero = HeroicFightUI.choosingHeroes.FIGHTING;
			this.doneMoving.setVisible(true);
			this.advanceFighters();
		}
		myUI.repaint();
	}

	public void addCounterCaller(Hero hero) {
		// Assumes counter buttons have been cleaned up
		
		UI.messageLog.add(hero.toChoiceString() + " is calling a heroic fight!");
		// Decide who gets to go first
		int firstSide = UI.rng.nextInt(2);
		
		UI.messageLog.add(Game.armyTitles[firstSide] + " has won the coinflip and will be fighting first");
		// Add him in depending on who's going to be going first
		if (firstSide == hero.armyIndex){
			this.callingHeroes.add(0, hero);
		}
		else {
			this.callingHeroes.add(hero);
		}
		
		// If the first side can continue, set them as the next to select in multiple
		if (this.heroicFightPossible(firstSide)) {
			this.selectingArmy = firstSide;
			UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call or select done");
			this.choosingHero = HeroicFightUI.choosingHeroes.MULTIPLE;
			this.doneChoosing.setVisible(true);
		}
		// Otherwise, set to second side if they have more options
		else if (this.heroicFightPossible((firstSide+1)%2)) {
			UI.messageLog.add(Game.armyTitles[firstSide] + " is out of heroes that can call a fight");
			this.selectingArmy = (firstSide+1)%2;
			UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call a fight or select done");
			this.choosingHero = HeroicFightUI.choosingHeroes.MULTIPLE;
			this.bothChoosing = false;
			this.doneChoosing.setVisible(true);
		}
		// Otherwise, just be done
		else {
			UI.messageLog.add("Both sides are out of heroes that can call a fight");
			this.choosingHero = HeroicFightUI.choosingHeroes.FIGHTING;
			this.doneMoving.setVisible(true);
			this.advanceFighters();
		}
		myUI.repaint();
	}

	public void addCallingHero(Hero hero) {
		hero.useMight(1);
		this.callingHeroes.add(hero);
		UI.messageLog.add(hero.toChoiceString() + " is calling a heroic fight!");
		if (this.bothChoosing) {
			int newSelectingArmy = (this.selectingArmy+1)%2;
			if (this.heroicFightPossible(newSelectingArmy)) {
				this.selectingArmy = newSelectingArmy;
				UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call a fight or select done");
			}
			else {
				UI.messageLog.add(Game.armyTitles[newSelectingArmy] + " is out of heroes that can call a fight");
				UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call a fight or select done");
				this.bothChoosing = false;
				// Not both choosing anymore, continue with this army
			}
		}
		if (!this.heroicFightPossible(this.selectingArmy)) {
			// No more heroes can call, fight on to actually fighting
			this.choosingHero = HeroicFightUI.choosingHeroes.FIGHTING;
			this.doneChoosing.setVisible(false);
			this.advanceFighters();
		}
		else {
			UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call a fight or select done");
		}
	}
	
	public void advanceFighters() {
		// TODO: FIX THIS UP
		
		myUI.selectedUnit = null;
		myUI.targetedUnit = null;
		if (this.callingHeroes.size() == 0) {
			// Move on to normal fight phase
			this.endPhase();
		}
		else {
			Hero nextHero = this.callingHeroes.get(0);
			this.callingHeroes.remove(0);
			this.currentHero = nextHero;
			if (nextHero.getWounds() <= 0 || nextHero.battle == null) {
				// He died or got out of battle before getting to call his fight
				this.advanceFighters();
			}
			else {
				// We have an actual caller, start his fight
				doneMoving.setVisible(false);
				this.choosingHero = HeroicFightUI.choosingHeroes.FIGHTING;
				myUI.selectedBattle = currentHero.battle;
				
				if (myUI.selectedBattle != null && myUI.game.battles.contains(myUI.selectedBattle)) {
					goodChoice = new Choice();
					badChoice = new Choice();
					
					// Populate the unit choices
					for(Unit u : myUI.selectedBattle.goodUnits) {
						goodChoice.add(u.toChoiceString());
					}
					for(Unit u : myUI.selectedBattle.badUnits) {
						badChoice.add(u.toChoiceString());
					}
					goodChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
					badChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 30);
					Unit goodUnit = myUI.selectedBattle.goodUnits.get(0);
					int count = 0;
					for (Equipment equip : goodUnit.equipmentList) {
						if (equip.options != null) {
							equip.options.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 60 - 30*count);
							myUI.add(equip.options);
							count += 1;
						}
					}
					Unit badUnit = myUI.selectedBattle.badUnits.get(0);
					count = 0;
					for (Equipment equip : badUnit.equipmentList) {
						if (equip.options != null) {
							equip.options.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 60 + 30*count);
							myUI.add(equip.options);
							count += 1;
						}
					}
					ItemListener i = new ItemListener() {
						public void itemStateChanged(ItemEvent e) {
							myUI.removeByName("Equipment Options");
							Unit goodUnit = myUI.selectedBattle.goodUnits.get(goodChoice.getSelectedIndex());
							int count = 0;
							for (Equipment equip : goodUnit.equipmentList) {
								if (equip.options != null) {
									equip.options.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 60 - 30*count);
									myUI.add(equip.options);
									count += 1;
								}
							}
							Unit badUnit = myUI.selectedBattle.badUnits.get(badChoice.getSelectedIndex());
							count = 0;
							for (Equipment equip : badUnit.equipmentList) {
								if (equip.options != null) {
									equip.options.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 60 + 30*count);
									myUI.add(equip.options);
									count += 1;
								}
							}
						}
					};
					goodChoice.addItemListener(i);
					badChoice.addItemListener(i);

					myUI.add(goodChoice);
					myUI.add(badChoice);
					
					fightBattle.setEnabled(false);
					rollDice.setVisible(true);
					
					myUI.revalidate();
					myUI.repaint();
				}
			}
		}
	}
	
	public void refreshMoves() {
		
	}

	public void selectUnit(Unit u) {
		myUI.selectedUnit = u;
		
		// Remove previous buttons
		for (Button b : moveOptions){
			myUI.remove(b);
		}
		
		moveOptions = new ArrayList<Button>();
		
		// Get buttons for new unit, but only if it's in our army (should never happen, so commented out for now to reuse this function in HeroicMove.
		// If issues arise, may need to copy code over into heroic move)
		//if (!movingUnits.contains(u)) 
		//	return;
		int buttonCount = 0;
		// First, check for terrain
		Button terrainInteract = u.getTerrainInteract();
		if (terrainInteract != null){
			terrainInteract.setBounds(myUI.dim.width-200, 200+60*buttonCount, 80, 50);
			moveOptions.add(terrainInteract);
			myUI.add(terrainInteract);
			buttonCount++;
		}
		// Then check for standing up and laying down
		if (u.layingDown && u.moveLeft >= 0.5) {
			// Make a stand up button
			Button standUp = new Button("Stand up");
			standUp.setBounds(myUI.dim.width-200, 200+60*buttonCount, 80, 50);
			standUp.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					u.standUp();
					myUI.selectUnit(u);
				}
			});
			moveOptions.add(standUp);
			myUI.add(standUp);
			buttonCount++;
		}
		else if (!u.layingDown && u.moveLeft >= u.move / 2) {
			// Make a lay down button
			Button layDown = new Button("Lay down");
			layDown.setBounds(myUI.dim.width-200, 200+60*buttonCount, 80, 50);
			layDown.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					u.layDown();
					myUI.selectUnit(u);
				}
			});
			moveOptions.add(layDown);
			myUI.add(layDown);
			buttonCount++;
		}
		
		// Can't use magic (what about throwing weapons?)
	}
	
	public void endPhase() {
		// Transition to normal fight Phase
		// Clean up fight stuff
		myUI.removeMouseListener(myMouse);
		myUI.removeMouseMotionListener(myMouse);
		
		// Clean up various Buttons and Panels
		if (targetStats != null) {
			myUI.remove(targetStats);
			myUI.remove(goodHeroicFight);
			myUI.remove(badHeroicFight);
			myUI.remove(skipHeroicFight);
			myUI.remove(counterCall);
			myUI.remove(skipCounter);
			myUI.remove(doneChoosing);
			myUI.remove(doneMoving);
		}
		
		if (choosingHero != HeroicFightUI.choosingHeroes.NONE)
			UI.messageLog.add("Finished Heroic Fights, moving to normal Fight Phase");
		
		myUI.endPhase.setEnabled(true);
		myUI.selectedUnit = null;
		myUI.targetedUnit = null;
		
		// Create a fightUI and set it to be the new phase
		FightUI fightUI = new FightUI();
		fightUI.myUI = myUI;
		myUI.phaseUI = fightUI;
		myUI.phaseUI.beginPhase();
		myUI.repaint();
	}
	
	public void updateTargetPanel() {
		if (myUI.targetedUnit != null) {
			((Label)targetStats.getComponent(1)).setText("Move Left: " + String.format("%.2f", myUI.targetedUnit.moveLeft));
			((Label)targetStats.getComponent(2)).setText("Strength: " + myUI.targetedUnit.getStrength());
			((Label)targetStats.getComponent(3)).setText("Defense: " + myUI.targetedUnit.getDefense());
			((Label)targetStats.getComponent(4)).setText("Attacks: " + myUI.targetedUnit.getAttacks());
			((Label)targetStats.getComponent(5)).setText("Wounds: " + myUI.targetedUnit.getWounds());
			((Label)targetStats.getComponent(6)).setText("Courage: " + myUI.targetedUnit.getCourage());
			((Label)targetStats.getComponent(7)).setText("FightValue: " + myUI.targetedUnit.getFightValue());
			((Label)targetStats.getComponent(8)).setText("ShootValue: " + myUI.targetedUnit.getShootValue());
			((Label)targetStats.getComponent(9)).setText("Mt/Wl/Ft: " + myUI.targetedUnit.getMight()+myUI.targetedUnit.getWill()+myUI.targetedUnit.getFate());
		}
	}
	
	public void paint(Graphics bufferG) {
    	if (myUI.targetedUnit != null){
    		bufferG.setColor(Color.red);
    		bufferG.drawOval(myUI.targetedUnit.x-(myUI.targetedUnit.pixelRadius+1)-myUI.boardOffsetX, 
    						myUI.targetedUnit.y-(myUI.targetedUnit.pixelRadius+1)-myUI.boardOffsetY, 
    						2*(myUI.targetedUnit.pixelRadius+1), 2*(myUI.targetedUnit.pixelRadius+1));
    		bufferG.setColor(Color.black);
    	}
    	// Draw ovals for units able to move
    	((Graphics2D)bufferG).setStroke(new BasicStroke(2));
		bufferG.setColor(Color.ORANGE);
    	for (Unit u : movingUnits) {
    		bufferG.drawOval(u.x-(u.pixelRadius+2)-myUI.boardOffsetX, u.y-(u.pixelRadius+2)-myUI.boardOffsetY,
    						2*(u.pixelRadius+2), 2*(u.pixelRadius+2));
    	}
    	bufferG.setColor(Color.BLACK);
		((Graphics2D)bufferG).setStroke(new BasicStroke());
		
		updateTargetPanel();
	}
	
	
	public void setupButtons() {
		fightBattle = new Button("Fight Battle");
		fightBattle.setBounds(myUI.dim.width-100,50,100,50);
		fightBattle.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (myUI.selectedBattle != null && myUI.game.battles.contains(myUI.selectedBattle)) {
					goodChoice = new Choice();
					badChoice = new Choice();
					
					// Populate the unit choices
					for(Unit u : myUI.selectedBattle.goodUnits) {
						goodChoice.add(u.toChoiceString());
					}
					for(Unit u : myUI.selectedBattle.badUnits) {
						badChoice.add(u.toChoiceString());
					}
					goodChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
					badChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 30);
					Unit goodUnit = myUI.selectedBattle.goodUnits.get(0);
					int count = 0;
					for (Equipment equip : goodUnit.equipmentList) {
						if (equip.options != null) {
							equip.options.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 60 - 30*count);
							myUI.add(equip.options);
							count += 1;
						}
					}
					Unit badUnit = myUI.selectedBattle.badUnits.get(0);
					count = 0;
					for (Equipment equip : badUnit.equipmentList) {
						if (equip.options != null) {
							equip.options.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 60 + 30*count);
							myUI.add(equip.options);
							count += 1;
						}
					}
					ItemListener i = new ItemListener() {
						public void itemStateChanged(ItemEvent e) {
							myUI.removeByName("Equipment Options");
							Unit goodUnit = myUI.selectedBattle.goodUnits.get(goodChoice.getSelectedIndex());
							int count = 0;
							for (Equipment equip : goodUnit.equipmentList) {
								if (equip.options != null) {
									equip.options.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 60 - 30*count);
									myUI.add(equip.options);
									count += 1;
								}
							}
							Unit badUnit = myUI.selectedBattle.badUnits.get(badChoice.getSelectedIndex());
							count = 0;
							for (Equipment equip : badUnit.equipmentList) {
								if (equip.options != null) {
									equip.options.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 60 + 30*count);
									myUI.add(equip.options);
									count += 1;
								}
							}
						}
					};
					goodChoice.addItemListener(i);
					badChoice.addItemListener(i);

					myUI.add(goodChoice);
					myUI.add(badChoice);
					
					fightBattle.setEnabled(false);
					rollDice.setVisible(true);
					
					myUI.revalidate();
					myUI.repaint();
				}
			}
		});
		myUI.add(fightBattle);
		
		
		
		
		rollDice = new Button("Roll Dice");
		rollDice.setBounds(myUI.dim.width-100,100,100,50);
		rollDice.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				// Apply the chosen options
				for (Unit u : myUI.selectedBattle.goodUnits) {
					u.battleDice = u.attacks;
					u.battleBonus = 0;
					u.woundDice = u.attacks;
					u.woundBonus = 0;
					for (Equipment equip : u.equipmentList) {
						equip.applyOptions();
					}
				}
				for (Unit u : myUI.selectedBattle.badUnits) {
					u.battleDice = u.attacks;
					u.battleBonus = 0;
					u.woundDice = u.attacks;
					u.woundBonus = 0;
					for (Equipment equip : u.equipmentList) {
						equip.applyOptions();
					}
				}
				// Clean up choices
				myUI.remove(goodChoice);
				myUI.remove(badChoice);
				myUI.removeByName("Equipment Options");
				rollDice.setVisible(false);
				
				// Where we go next is dependent on what kind of battle we're dealing with
				if (!(myUI.selectedBattle instanceof BarrierBattle)){
					// Move to next stage
					myUI.storeVisibleComponents();
					myUI.disableComponents();
					myUI.selectedBattle.rollFightDice(doneRetreating);
				}
				else if (myUI.selectedBattle instanceof BarrierBattle) {
					// How we handle the barrier fight depends on:
					//    - Which side is outnumbered (if one defender, do multiple fights)
					//    - Whether the attack is coming from both sides (No obstacle bonus when striking)
					if (((BarrierBattle)myUI.selectedBattle).getAttackers().size() == 1) {
						// Only need to do one normal fight
						attackers = new Choice();
						targets = new Choice();
						attackers.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
						targets.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 30);
						myUI.storeVisibleComponents();
						myUI.disableComponents();
						((BarrierBattle)myUI.selectedBattle).rollBarrierFightDice(doneRetreating, barrierStrikeButton, 
																	attackers, targets);  // Only adds retreat move if defender won
					}
					else if (((BarrierBattle)myUI.selectedBattle).getAttackers().size() > 1) {
						// Need to set up multiple fights somehow, bring back whichever the appropriate choice is to choose who attacks first
						// Then do fights one at a time until either the defender list is empty - advance over barrier
						// or all have fought (then need to retreat all)
						if (!((BarrierBattle)myUI.selectedBattle).attackFromBothSides) {
							barrierAttackerChoice = new Choice();
							barrierAttackerChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
							for (Unit u : ((BarrierBattle)myUI.selectedBattle).getAttackers()) {
								barrierAttackerChoice.add(u.toChoiceString());
							}
							myUI.add(barrierAttackerChoice);
							
							chargeBarrier.setVisible(true);
						}
						else {
							// Being attacked from both sides, treat it like a normal fight
							myUI.storeVisibleComponents();
							myUI.disableComponents();
							myUI.selectedBattle.rollFightDice(doneRetreating);
						}
					}
				}
				
				myUI.revalidate();
				myUI.repaint();
			}
		});
		myUI.add(rollDice);
		rollDice.setVisible(false);
		
		
		
		
		
		chargeBarrier = new Button("Charge Barrier");
		chargeBarrier.setBounds(myUI.dim.width-100, 100, 100, 50);
		chargeBarrier.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				chargeBarrier.setVisible(false);
				// Get the selected unit from barrierAttackerChoice
				Unit charger = Utils.getFromListByString(((BarrierBattle)myUI.selectedBattle).getAttackers(), 
														  barrierAttackerChoice.getSelectedItem());
				
				attackers = new Choice();
				targets = new Choice();
				attackers.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
				targets.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 30);
				// do a fight between defender and attacker
				myUI.storeVisibleComponents();
				myUI.disableComponents();
				((BarrierBattle)myUI.selectedBattle).rollDiceOneAttacker(charger, doneRetreating, barrierStrikeButton, attackers, targets);
				
				// do visibility/enable UI stuff (also happens throughout for various branching results)
				myUI.remove(barrierAttackerChoice);
				chargeBarrier.setVisible(false);
				myUI.revalidate();
				myUI.repaint();
			}
		});
		myUI.add(chargeBarrier);
		chargeBarrier.setVisible(false);
		
		
		
		
		doneRetreating = new Button("Done Retreating");
		doneRetreating.setBounds(myUI.dim.width-100, 100, 100, 50);
		doneRetreating.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				for (Unit u : myUI.selectedBattle.losers) {
					if (u.moveLeft > 0.2 || u.isTransfixed || u.layingDown) {
						u.hasRetreated = false;
						UI.messageLog.add(u.toChoiceString() + " doesn't retreat");
					}
				}
				
				doneRetreating.setVisible(false);
				
				// Add strike paraphernalia
				attackers = new Choice();
				targets = new Choice();
				attackers.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
				targets.setLocation(myUI.dim.width - 200, myUI.dim.height/2 + 30);
				for (Unit u : myUI.selectedBattle.winners) {
					if (u.layingDown) {
						// Stand up
						u.layingDown = false;
					}
					else {
						for (int i = 0; i < u.getWoundDice(); i++) {
							attackers.add(u.toChoiceString());
						}
					}
				}
				for (Unit u : myUI.selectedBattle.losers) {
					if (u.hasRetreated)
						targets.add(u.toChoiceString());
					else
						targets.add(u.toChoiceString() + "-(T)");
				}
				
				// If the winning side was laying down, they may need to stand up instead of striking
				if (attackers.getItemCount() == 0 || targets.getItemCount() == 0) {
					myUI.selectedBattle.cleanUp();
					
					advanceFighters();
					return;
				}
				
				// Otherwise, do stuff
				myUI.add(attackers);
				myUI.add(targets);
				
				if (myUI.selectedBattle instanceof BarrierBattle && !((BarrierBattle)myUI.selectedBattle).attackFromBothSides)
					barrierStrikeButton.setVisible(true);
				else {
					strikeButton.setVisible(true);
				}
				
				myUI.revalidate();
				myUI.repaint();
			}
		});
		myUI.add(doneRetreating);
		doneRetreating.setVisible(false);
		
		
		
		
		barrierDoneFallingBack = new Button("Done Falling Back");
		barrierDoneFallingBack.setBounds(myUI.dim.width-100, 100, 100, 50);
		barrierDoneFallingBack.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				for (Unit u : ((BarrierBattle)myUI.selectedBattle).getAttackers()) {
					if (u.moveLeft == 1) {
						UI.messageLog.add("Someone hasn't fallen back");
						return;
					}
				}
				
				barrierDoneFallingBack.setVisible(false);
				
				ArrayList<Unit> unfought = new ArrayList<Unit>();
				for (Unit u : ((BarrierBattle)myUI.selectedBattle).getAttackers()) {
					if (u.hasFought == false) {
						unfought.add(u);
					}
				}
				if (unfought.size() == 0) {
					myUI.selectedBattle.cleanUp();
					
					// End of a fight where someone on each side is alive, move on to next heroic fight
					advanceFighters();
					return;
				}
				else {
					// need to re-enable chargeBarrier and refresh+reenable the charge barrier choice
					barrierAttackerChoice = new Choice();
					barrierAttackerChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
					for (Unit u : unfought) {
						barrierAttackerChoice.add(u.toChoiceString());
					}
					myUI.add(barrierAttackerChoice);
					
					chargeBarrier.setVisible(true);
				}
				myUI.revalidate();
				myUI.repaint();
			}
		});
		myUI.add(barrierDoneFallingBack);
		barrierDoneFallingBack.setVisible(false);
		
		
		
		
		
		strikeButton = new Button("Strike");
		strikeButton.setBounds(myUI.dim.width-100, 100, 100, 50);
		strikeButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Unit attacker = myUI.selectedBattle.getSelectedUnit(attackers);
				Unit target = myUI.selectedBattle.getSelectedUnit(targets);
				
				// Strike
				Button doneStriking = new Button();
				doneStriking.addMouseListener(new MouseListener() {
					public void mouseClicked(MouseEvent e) {						
						// Remove attacker
						attackers.remove(attackers.getSelectedIndex());
						
						// Remove target if dead
						if(target.getWounds() <= 0)
							targets.remove(targets.getSelectedIndex());
						
						
						// Check for end conditions
						if (attackers.getItemCount() == 0 || targets.getItemCount() == 0) {
							myUI.selectedBattle.cleanUp();
							strikeButton.setVisible(false);
							myUI.remove(attackers);
							myUI.remove(targets);
							
							// If we killed all our enemies, transition to movement phase
							if (myUI.selectedBattle.getUnitsByIndex((currentHero.armyIndex+1)%2).size() <= 0) {
								choosingHero = HeroicFightUI.choosingHeroes.MOVING;
								refreshMoves();
							}
							else {
								advanceFighters();
							}
						}
						myUI.remove(doneStriking);
						myUI.refreshSelectChoice();
						myUI.revalidate();
						myUI.repaint();
					}
					public void mouseEntered(MouseEvent arg0) {}
					public void mouseExited(MouseEvent e) {}
					public void mousePressed(MouseEvent e) {}
					public void mouseReleased(MouseEvent e) {}
				});
				attacker.strike(target, target.hasRetreated, doneStriking);

				myUI.refreshSelectChoice();
				myUI.revalidate();
				myUI.repaint();
			}
		});
		myUI.add(strikeButton);
		strikeButton.setVisible(false);
		
		
		barrierStrikeButton = new Button("Strike!");
		barrierStrikeButton.setBounds(myUI.dim.width-100, 100, 100, 50);
		barrierStrikeButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Unit attacker = myUI.selectedBattle.getSelectedUnit(attackers);
				Unit target = myUI.selectedBattle.getSelectedUnit(targets);
				
				attackers.setEnabled(false);
				targets.setEnabled(false);
				
				Button doneStriking = new Button();
				doneStriking.addMouseListener(new MouseListener() {
					public void mouseClicked(MouseEvent e){
						attackers.setEnabled(true);
						targets.setEnabled(true);
						
						// Remove attacker
						attackers.remove(attackers.getSelectedIndex());
						
						// Remove target if dead
						if(target.getWounds() <= 0) {
							targets.remove(targets.getSelectedIndex());
							((BarrierBattle)myUI.selectedBattle).perishedUnits.add(target);
							if (attacker.armyIndex != ((BarrierBattle)myUI.selectedBattle).defenderIndex) {
								UI.messageLog.add("Killed enemy " + target.toChoiceString() + ", taking the barricade!");
								// If only one attacker, take space of killed unit
								if (myUI.selectedBattle.getUnitsByIndex(attacker.armyIndex).size() == 1) {
									attacker.x = target.x;
									attacker.y = target.y;
								}
								// Otherwise we have multiple attackers against a single unit, any who haven't fought can cross
								else {
									int numJumped = 0;
									((BarrierBattle)myUI.selectedBattle).barrier.takeBarrier(attacker);
									for (Unit u : myUI.selectedBattle.getUnitsByIndex(attacker.armyIndex)) {
										if (u.hasFought == false) {
											int oldX = u.x;
											int oldY = u.y;
											((BarrierBattle)myUI.selectedBattle).barrier.takeBarrier(u);
											if (u.x != oldX || u.y != oldY) 
												numJumped += 1;
										}
									}
									if (numJumped == 0){
										attacker.x = target.x;
										attacker.y = target.y;
									}
								}
							}
						}
						
						boolean normalCleanup = false;
						ArrayList<Unit> unfought = new ArrayList<Unit>();
						for (Unit u : ((BarrierBattle)myUI.selectedBattle).getAttackers()) {
							if (u.hasFought == false) {
								unfought.add(u);
							}
						}
						// Check for end conditions
						if (attackers.getItemCount() == 0) {
							if (target.getWounds() > 0 && target.armyIndex == ((BarrierBattle)myUI.selectedBattle).defenderIndex) {
								// If target is still alive and striker is an attacker, need to fall back
								attacker.uncontactTerrain();
								attacker.uncontactUnits();
								attacker.moveLeft = 1;
								for (Unit ally : attacker.army.units) {
									if (Utils.inchDist(attacker, ally) < 2 && ally.battle == null) {
										ally.moveLeft = 1;
									}
								}
								barrierStrikeButton.setVisible(false);
								myUI.remove(attackers);
								myUI.remove(targets);
								barrierDoneFallingBack.setVisible(true);
							}
							else if (target.getWounds() <= 0 && target.armyIndex == ((BarrierBattle)myUI.selectedBattle).defenderIndex) {
								// Killed the target, do normal cleanup (already advanced over barricade)
								normalCleanup = true;
							}
							else {
								// Defender won, check whether or not battle is finished
								if (unfought.size() == 0)
									normalCleanup = true;
								else {
									barrierAttackerChoice = new Choice();
									barrierAttackerChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
									for (Unit u : unfought) {
										barrierAttackerChoice.add(u.toChoiceString());
									}
									myUI.add(barrierAttackerChoice);
									myUI.remove(attackers);
									myUI.remove(targets);
									
									chargeBarrier.setVisible(true);
								}
							}
						}
						else if (targets.getItemCount() == 0) {
							// target is dead, if it was defender to normal cleanup, otherwise reset chargeBarrier
							if (target.armyIndex == ((BarrierBattle)myUI.selectedBattle).defenderIndex)
								normalCleanup = true;
							else {
								if (unfought.size() == 0)
									normalCleanup = true;
								else {
									barrierAttackerChoice = new Choice();
									barrierAttackerChoice.setLocation(myUI.dim.width - 200, myUI.dim.height/2 - 30);
									for (Unit u : unfought) {
										barrierAttackerChoice.add(u.toChoiceString());
									}
									myUI.add(barrierAttackerChoice);
									myUI.remove(attackers);
									myUI.remove(targets);
									
									chargeBarrier.setVisible(true);
								}
							}
						}
						if (normalCleanup) {
							myUI.selectedBattle.cleanUp();
							barrierStrikeButton.setVisible(false);
							myUI.remove(attackers);
							myUI.remove(targets);
							
							// If we killed all our enemies, transition to movement phase
							if (myUI.selectedBattle.getUnitsByIndex((currentHero.armyIndex+1)%2).size() <= 0) {
								choosingHero = HeroicFightUI.choosingHeroes.MOVING;
								refreshMoves();
							}
							else {
								advanceFighters();
							}
						}
						myUI.refreshSelectChoice();
						myUI.revalidate();
						myUI.repaint();
					}
					public void mouseEntered(MouseEvent e) {}
					public void mouseExited(MouseEvent e) {}
					public void mousePressed(MouseEvent e) {}
					public void mouseReleased(MouseEvent e) {}
				});
				
				
				if (attacker.armyIndex != ((BarrierBattle)myUI.selectedBattle).defenderIndex){
					// Roll for barrier
					DieRoll barrierRoll = new DieRoll(attacker, myUI.dim.width-200, myUI.dim.height/2-130, 
										 			   "4+ to pass barrier", myUI);
					
					if (!barrierRoll.isModifiable()){
						int barrierNum = barrierRoll.getRoll();
						UI.messageLog.add("Rolling to strike past barrier: " + barrierRoll);
						if (barrierNum > 3) {
							// Strike
							attacker.strike(target, doneStriking);
						}
					}
					else {
						myUI.storeVisibleComponents();
						myUI.disableComponents();
						ActionListener mightDone = new ActionListener() {
							public void actionPerformed(ActionEvent e) {
								int barrierNum = barrierRoll.getRoll();
								UI.messageLog.add("Rolling to strike past barrier: " + barrierRoll);
								myUI.reenableComponents();
								myUI.disableMight();
								if (barrierNum > 3) {
									// Strike
									attacker.strike(target, doneStriking);
								}
							}
						};
						myUI.enableMight(mightDone);
					}
				}
				else {
					attacker.strike(target, target.hasRetreated, doneStriking);
				}
				
				myUI.refreshSelectChoice();
				myUI.revalidate();
				myUI.repaint();
			}
		});
		myUI.add(barrierStrikeButton);
		barrierStrikeButton.setVisible(false);
	}
}
